<html>
    <head>
        <title>默认解决方案 和 数据库配置</title>
    </head>
    <body>
        <script>
             /*
                         二、默认解决方案 和 数据库配置

                                当你创建一个新的Web应用程序（使用EF Core，这是默认的数据库提供程序）时，你的解决方案结构将类似于下图：

                                        《图片略，就是标准的分层解决方案》

                                1、数据库结构

                                                启动模板预装了一些应用程序模块。解决方案的每一层都有相应的模块包引用。
                                                
                                                因此，.EntityFrameworkCore项目具有.EntityFrameworkCore使用模块的包：

                                                《图片略，就是基础层默认的包引用》

                                                通过这种方式，你可以收集.EntityFrameworkCore项目下的所有关于EF Core的依赖包。 

                                                虽然每个模块在设计上都有自己的DbContext类，并且可以使用其自己的物理数据库，

                                                但解决方案配置为使用单个共享数据库，如下图所示：

                                                《图片略，大体意思是每个模块都有单独的DbContext，虽然可以拥有自己的独立数据库，但是默认分层解决方案中配置为每个模块共同使用默认数据库》

                                                这是最简单的配置，适用于大多数应用程序。
                                                
                                                appsettings.json文件有一个单连接字符串，名为Default：

                                                        "ConnectionStrings": {
                                                            "Default": "..."
                                                        }

                                                因此，你有一个单个数据库模式，其中包含共享此数据库的模块的所有表。

                                                ABP的连接字符串系统允许你轻松地为所需模块设置不同的连接字符串：

                                                    "ConnectionStrings": {
                                                        "Default": "...",
                                                        "AbpAuditLogging": "..."
                                                    }
                                                    
                                                    示例配置告诉ABP使用审核日志模块的第二个连接字符串（如果你没有为模块指定连接字符串，它会使用Default连接字符串）。

                                                但是，只有当具有给定连接字符串的审计日志数据库可用时，这才能工作。

                                                因此，你需要创建第二个数据库，在其中创建审计日志表并维护数据库表。

                                                如果你手动执行所有这些操作，没有问题。
                                                
                                                但是，推荐的方法是代码优先迁移。本文档的主要目的之一是指导你了解此类数据库分离场景

                                                
                                                ★、模块表

                                                        每个模块都使用其自己的数据库表。例如，Identity Module有一些表来管理系统中的用户和角色。

                                                        ①、表前缀

                                                                由于允许所有模块共享单个数据库（这是默认配置），因此模块通常使用表名前缀对其自己的表进行分组。

                                                                基本模块，如Identity、租户管理和审核日志，使用Abp前缀，而其他一些模块使用自己的前缀。

                                                                Identity Server模块使用IdentityServer前缀。

                                                                如果需要，你可以更改应用程序模块的数据库表名前缀。
                                                                
                                                                例子：

                                                                    Volo.Abp.IdentityServer.AbpIdentityServerDbProperties.DbTablePrefix = "Ids";

                                                                此代码更改了Identity Server模块的前缀。在应用程序的开头编写此代码。


                                                                （每个模块还定义了DbSchema属性（靠近DbTablePrefix），因此你可以为支持模式使用的数据库设置它。）


                                                

                                2、.EntityFrameworkCore 项目

                                        该解决方案包含一个项目，其名称以.EntityFrameworkCore。

                                        此项目具有应用程序的DbContext类（BookStoreDbContext对于此示例）。

                                        每个模块都使用自己的DbContext类来访问数据库。同样，你的应用程序有自己的DbContext。

                                        你通常在应用程序代码中使用此DbContext（如果你遵循最佳实践并将数据访问代码隐藏在存储库后面，则在你的存储库中）。

                                        它几乎是一个空的DbContext，因为你的应用程序一开始没有任何实体：

                                                        [ReplaceDbContext(typeof(IIdentityDbContext))]  // 替换IIdentityDbContext的默认实现
                                                        [ReplaceDbContext(typeof(ITenantManagementDbContext))]  // 替换ITenantManagementDbContext的默认实现
                                                        [ConnectionStringName("Default")]
                                                        public class BookStoreDbContext :
                                                            AbpDbContext<BookStoreDbContext>,
                                                            IIdentityDbContext,
                                                            ITenantManagementDbContext
                                                        {
                                                            //Add DbSet properties for your Aggregate Roots / Entities here. 
                                                                
                                                            // DbSet for entities from the replaced DbContexts 

                                                            public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options)
                                                                : base(options)
                                                            {

                                                            }

                                                            protected override void OnModelCreating(ModelBuilder builder)
                                                            {
                                                                base.OnModelCreating(builder);
                                                                
                                                                //* Include modules to your migration db context 
                                                                builder.ConfigurePermissionManagement();
                                                                builder.ConfigureSettingManagement();
                                                                builder.ConfigureBackgroundJobs();
                                                                builder.ConfigureAuditLogging();
                                                                builder.ConfigureIdentity();
                                                                builder.ConfigureIdentityServer();
                                                                builder.ConfigureFeatureManagement();
                                                                builder.ConfigureTenantManagement();

                                                                // Configure your own tables/entities here. Example:       
                                                                //builder.Entity<YourEntity>(b =>
                                                                //{
                                                                //    b.ToTable("YourEntities");
                                                                //    b.ConfigureByConvention(); //auto configure for the base properties
                                                                //    //...
                                                                //});
                                                            }
                                                        }
                                        这个DbContext类需要一些解释：

                                            ①、它使用[ReplaceDbContext]特性，替换了IIDentityDbContext、ITenantManagementDbContext的实现

                                                    这些属性在运行时用你的DbContext替换Identity和 TenantManagenment 模块的DbContext。
                                                    
                                                    这允许我们通过将你的实体与来自这些模块的实体（通过存储库）连接来轻松执行LINQ查询。

                                            ②、它定义了一个[ConnectionStringName]属性，告诉ABP始终为此Dbcontext使用Default连接字符串。

                                            ③、它继承自AbpDbContext<T>而不是标准的DbContext类。

                                                    你可以查看EF Core集成文档了解更多信息。现在，知道AbpDbContext<T>基类实现了ABP的一些约定，为你自动执行一些常见任务。

                                            ④、它为替换的DbContexts中的实体声明了DbSet属性（通过实现相应的接口）。

                                                      这些DbSet属性未在上面显示（为简洁起见），但你可以在region中的应用程序代码中找到。
                                                      
                                            ⑤、构造函数采用DbContextOptions<T>实例，并将其传递给基类。

                                            ⑥、它覆盖OnModelCreating方法来定义EF Core映射。
                                                                    
                                                        它首先调用base.OnModelCreating方法让ABP为我们实现基础的映射。

                                                        然后它为使用的模块调用一些builder.ConfigureXXX()方法。

                                                        这使得将这些模块的数据库映射添加到此DbContext成为可能，因此当我们添加新的EF Core数据库迁移时，它会创建模块的数据库表。

                                                        你可以按照示例代码中的注释为自己的实体配置映射。此时，你还可以更改正在使用的模块的映射。


                    */

        </script>
    </body>
</html>